<html><head><meta charset="utf-8"><title>12 使用泛型拯救你的any-慕课专栏</title>
			<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
			<meta name="renderer" content="webkit">
			<meta property="qc:admins" content="77103107776157736375">
			<meta property="wb:webmaster" content="c4f857219bfae3cb">
			<meta http-equiv="Access-Control-Allow-Origin" content="*">
			<meta http-equiv="Cache-Control" content="no-transform ">
			<meta http-equiv="Cache-Control" content="no-siteapp">
			<link rel="apple-touch-icon" sizes="76x76" href="https://www.imooc.com/static/img/common/touch-icon-ipad.png">
			<link rel="apple-touch-icon" sizes="120x120" href="https://www.imooc.com/static/img/common/touch-icon-iphone-retina.png">
			<link rel="apple-touch-icon" sizes="152x152" href="https://www.imooc.com/static/img/common/touch-icon-ipad-retina.png">
			<link href="https://moco.imooc.com/captcha/style/captcha.min.css" rel="stylesheet">
			<link rel="stylesheet" href="https://www.imooc.com/static/moco/v1.0/dist/css/moco.min.css?t=201907021539" type="text/css">
			<link rel="stylesheet" href="https://www.imooc.com/static/lib/swiper/swiper-3.4.2.min.css?t=201907021539">
			<link rel="stylesheet" href="https://static.mukewang.com/static/css/??base.css,common/common-less.css?t=2.5,column/zhuanlanChapter-less.css?t=2.5,course/inc/course_tipoff-less.css?t=2.5?v=201907051055" type="text/css">
			<link charset="utf-8" rel="stylesheet" href="https://www.imooc.com/static/lib/ueditor/themes/imooc/css/ueditor.css?v=201907021539"><link rel="stylesheet" href="https://www.imooc.com/static/lib/baiduShare/api/css/share_style0_16.css?v=6aba13f0.css"></head>
			<body><div id="main">

<div class="container clearfix" id="top" style="display: block; width: 1134px;">
    
    <div class="center_con js-center_con l" style="width: 1134px;">
        <div class="article-con">
                            <!-- 买过的阅读 -->
                <div class="map">
                    <a href="/read" target="_blank"><i class="imv2-feather-o"></i></a>
                    <a href="/read/35" target="_blank">零基础学透 TypeScript</a>
                    <a href="" target="_blank">
                        <span>
                            / 2-9 12 使用泛型拯救你的any
                        </span>
                    </a>
                </div>

            


            <div class="art-title" style="margin-top: 0px;">
                12 使用泛型拯救你的any
            </div>
            <div class="art-info">
                
                <span>
                    更新时间：2019-06-12 16:37:49
                </span>
            </div>
            <div class="art-top">
                                <img src="https://img1.mukewang.com/5cf3c4d40001726f06400359.jpg" alt="">
                                                <div class="famous-word-box">
                    <img src="https://www.imooc.com/static/img/column/bg-l.png" alt="" class="bg1 bg">
                    <img src="https://www.imooc.com/static/img/column/bg-r.png" alt="" class="bg2 bg">
                    <div class="famous-word">人的一生可能燃烧也可能腐朽，我不能腐朽，我愿意燃烧起来！<p class="author">——奥斯特洛夫斯基</p></div>
                </div>
                            </div>
            <div class="art-content js-lookimg">
                <div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">在前面的小节中我们学习了any类型，当我们要表示一个值可以为任意类型的时候，则指定它的类型为any，比如下面这个例子：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">const</span> getArray <span class="token operator">=</span> <span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token keyword">any</span><span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">any</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>times<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">这个函数接受两个参数。第一个参数为任意类型的值，第二个参数为数值类型的值，默认为 5。函数的功能是返回一个以 times 为元素个数，每个元素都是 value 的数组。这个函数我们从逻辑上可以知道，传入的 value 是什么类型，那么返回的数组的每个元素也应该是什么类型。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">接下来我们实际用一下这个函数：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token function">getArray</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">getArray</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">我们调用了两次这个方法，使用 forEach 方法遍历得到的数组，在传入 forEach 的函数中获取当前遍历到的数组元素的 length 属性。第一次调用这个方法是没问题的，因为我们第一次传入的值为数组，得到的会是一个二维数组<code>[ [1], [1] ]</code>。每次遍历的元素为<code>[1]</code>，它也是数组，所以打印它的 length 属性是可以的。而我们第二次传入的是一个数字 2，生成的数组是<code>[2, 2, 2]</code>，访问 2 的 length 属性是没有的，所以应该报错，但是这里却不会报错，因为我们在定义<code>getArray</code>函数的时候，指定了返回值是<code>any</code>类型的元素组成的数组，所以这里遍历其返回值中每一个元素的时候，类型都是any，所以不管做任何操作都是可以的，因此，上面例子中第二次调用<code>getArray</code>的返回值每个元素应该是数值类型，遍历这个数组时我们获取数值类型的length属性也没报错，因为这里item的类型是any。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">所以要解决这种情况，泛型就可以搞定，接下来我们来学习泛型。</p>
</div><div class="cl-preview-section"><h3 id="简单使用">2.9.1. 简单使用</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">要解决上面这个场景的问题，就需要使用泛型了。泛型（Generics）是指在定义函数、接口或类的时候，不预先指定具体的类型，而在使用的时候再指定类型的一种特性。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">还拿上面这个例子中的逻辑来举例，我们既要允许传入任意类型的值，又要正确指定返回值类型，就要使用泛型。我们先来看怎么改写：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">const</span> getArray <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> T<span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">:</span> T<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>times<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">我们在定义函数之前，使用<code>&lt;&gt;</code>符号定义了一个泛型变量 T，这个 T 在这次函数定义中就代表某一种类型，它可以是基础类型，也可以是联合类型等高级类型。定义了泛型变量之后，你在函数中任何需要指定类型的地方使用 T 都代表这一种类型。比如当我们传入 value 的类型为数值类型，那么返回的数组类型<code>T[]</code>就表示<code>number[]</code>。现在我们再来调用一下这个 getArray 函数：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript">getArray<span class="token operator">&lt;</span><span class="token keyword">number</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
getArray<span class="token operator">&lt;</span><span class="token keyword">number</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 类型“number”上不存在属性“length”</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">我们在调用 getArray 的时候，在方法名后面使用<code>&lt;&gt;</code>传入了我们的泛型变量 T 的类型<code>number[]</code>，那么在定义 getArray 函数时使用 T 指定类型的地方，都会使用<code>number[]</code>指定。但是你也可以省略这个<code>&lt;number[]&gt;</code>，TypeScript 会根据你传入函数的 value 值的类型进行推断：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token function">getArray</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 类型“number”上不存在属性“length”</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><h3 id="泛型变量">2.9.2. 泛型变量</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">当我们使用泛型的时候，你必须在处理类型涉及到泛型的数据的时候，把这个数据当做任意类型来处理。这就意味着不是所有类型都能做的操作不能做，不是所有类型都能调用的方法不能调用。可能会有点绕口，我们来看个例子：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">const</span> getLength <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>param<span class="token punctuation">:</span> T<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> param<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token comment">// error 类型“T”上不存在属性“length”</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">当我们获取一个类型为泛型的变量 param 的 length 属性值时，如果 param 的类型为数组 Array 或字符串 string 类型是没问题的，它们有 length 属性。但是如果此时传入的 param 是数值 number 类型，那这里就会有问题了。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">这里的<code>T</code>并不是固定的，你可以写为<code>A</code>、<code>B</code>或者其他名字，而且还可以在一个函数中定义多个泛型变量。我们来看个复杂点的例子：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">const</span> getArray <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token punctuation">,</span> U<span class="token operator">&gt;</span><span class="token punctuation">(</span>param1<span class="token punctuation">:</span> T<span class="token punctuation">,</span> param2<span class="token punctuation">:</span> U<span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>T<span class="token punctuation">,</span> U<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>times<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token punctuation">[</span>param1<span class="token punctuation">,</span> param2<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">getArray</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>item <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// error 类型“number”上不存在属性“length”</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>item<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// error 属性“toFixed”在类型“string”上不存在</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">这个例子中，我们定义了两个泛型变量<code>T</code>和<code>U</code>。第一个参数的类型为 T，第二个参数的类型为 U，最后函数返回一个二维数组，函数返回类型我们指定是一个元素类型为<code>[T, U]</code>的数组。所以当我们调用函数，最后遍历结果时，遍历到的每个元素都是一个第一个元素是数值类型、第二个元素是字符串类型的数组。</p>
</div><div class="cl-preview-section"><h3 id="泛型函数类型">2.9.3. 泛型函数类型</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">我们可以定义一个泛型函数类型，还记得我们之前学习函数一节时，给一个函数定义函数类型，现在我们可以使用泛型定义函数类型：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token comment">// ex1: 简单定义</span>
<span class="token keyword">const</span> getArray<span class="token punctuation">:</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>arg<span class="token punctuation">:</span> T<span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> T<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">(</span>arg<span class="token punctuation">,</span> times<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>times<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token comment">// ex2: 使用类型别名</span>
<span class="token keyword">type</span> GetArray <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>arg<span class="token punctuation">:</span> T<span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> T<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> getArray<span class="token punctuation">:</span> GetArray <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>arg<span class="token punctuation">:</span> T<span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> T<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>times<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">当然了，我们也可以使用接口的形式来定义泛型函数类型：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">interface</span> <span class="token class-name">GetArray</span> <span class="token punctuation">{</span>
  <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>arg<span class="token punctuation">:</span> T<span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> T<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> getArray<span class="token punctuation">:</span> GetArray <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>arg<span class="token punctuation">:</span> T<span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> T<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>times<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">你还可以把接口中泛型变量提升到接口最外层，这样接口中所有属性和方法都能使用这个泛型变量了。我们先来看怎么用：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">interface</span> <span class="token class-name">GetArray</span><span class="token operator">&lt;</span>T<span class="token operator">&gt;</span> <span class="token punctuation">{</span>
  <span class="token punctuation">(</span>arg<span class="token punctuation">:</span> T<span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> T<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  tag<span class="token punctuation">:</span> T<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> getArray<span class="token punctuation">:</span> GetArray<span class="token operator">&lt;</span><span class="token keyword">number</span><span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token operator">&gt;</span><span class="token punctuation">(</span>arg<span class="token punctuation">:</span> T<span class="token punctuation">,</span> times<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span><span class="token punctuation">:</span> T<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// error 不能将类型“{ &lt;T&gt;(arg: T, times: number): T[]; tag: string; }”分配给类型“GetArray&lt;number&gt;”。</span>
  <span class="token comment">// 属性“tag”的类型不兼容。</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>times<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
getArray<span class="token punctuation">.</span>tag <span class="token operator">=</span> <span class="token string">"a"</span><span class="token punctuation">;</span> <span class="token comment">// 不能将类型“"a"”分配给类型“number”</span>
<span class="token function">getArray</span><span class="token punctuation">(</span><span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 不能将类型“"a"”分配给类型“number”</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">上面例子中将泛型变量定义在接口最外层，所以不仅函数的类型中可以使用 T，在属性 tag 的定义中也可以使用。但在使用接口的时候，要在接口名后面明确传入一个类型，也就是这里的<code>GetArray&lt;number&gt;</code>，那么后面的 arg 和 tag 的类型都得是 number 类型。当然了，如果你还是希望 T 可以是任何类型，你可以把<code>GetArray&lt;number&gt;</code>换成<code>GetArray&lt;any&gt;</code>。</p>
</div><div class="cl-preview-section"><h3 id="泛型约束">2.9.4 泛型约束</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">当我们使用了泛型时，就意味着这个这个类型是任意类型。但在大多数情况下，我们的逻辑是对特定类型处理的。还记得我们前面讲泛型变量时举的那个例子——当访问一个泛型类型的参数的 length 属性时，会报错"类型“T”上不存在属性“length”"，是因为并不是所有类型都有 length 属性。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">所以我们在这里应该对 T 有要求，那就是类型为 T 的值应该包含 length 属性。说到这个需求，你应该能想到接口的使用，我们可以使用接口定义一个对象必须有哪些属性：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">interface</span> <span class="token class-name">ValueWithLength</span> <span class="token punctuation">{</span>
  length<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> v<span class="token punctuation">:</span> ValueWithLength <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// error Property 'length' is missing in type '{}' but required in type 'ValueWithLength'</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">泛型约束就是使用一个类型和<code>extends</code>对泛型进行约束，之前的例子就可以改为下面这样：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">interface</span> <span class="token class-name">ValueWithLength</span> <span class="token punctuation">{</span>
  length<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> getLength <span class="token operator">=</span> <span class="token operator">&lt;</span>T <span class="token keyword">extends</span> <span class="token class-name">ValueWithLength</span><span class="token operator">&gt;</span><span class="token punctuation">(</span>param<span class="token punctuation">:</span> T<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> param<span class="token punctuation">.</span>length<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">getLength</span><span class="token punctuation">(</span><span class="token string">"abc"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3</span>
<span class="token function">getLength</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3</span>
<span class="token function">getLength</span><span class="token punctuation">(</span><span class="token punctuation">{</span> length<span class="token punctuation">:</span> <span class="token number">3</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 3</span>
<span class="token function">getLength</span><span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// error 类型“123”的参数不能赋给类型“ValueWithLength”的参数</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">这个例子中，泛型变量T受到约束。它必须满足接口<em>ValueWithLength</em>，也就是不管它是什么类型，但必须有一个length属性，且类型为数值类型。例子中后面四次调用getLength方法，传入了不同的值，传入字符串<code>"abc"</code>、数组<code>[1, 2, 3]</code>和一个包含length属性的对象<code>{ length: 3 }</code>都是可以的，但是传入数值<code>123</code>不行，因为它没有length属性。</p>
</div><div class="cl-preview-section"><h3 id="在泛型约束中使用类型参数">2.9.4 在泛型约束中使用类型参数</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">当我们定义一个对象，想要对只能访问对象上存在的属性做要求时，该怎么办？先来看下这个需求是什么样子：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">const</span> <span class="token function-variable function">getProps</span> <span class="token operator">=</span> <span class="token punctuation">(</span>object<span class="token punctuation">,</span> propName<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> object<span class="token punctuation">[</span>propName<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> a<span class="token punctuation">:</span> <span class="token string">"aa"</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token string">"bb"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">getProps</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token string">"c"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// undefined</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">当我们访问这个对象的’c’属性时，这个属性是没有的。这里我们需要用到索引类型<code>keyof</code>结合泛型来实现对这个问题的检查。索引类型在高级类型一节会详细讲解，这里你只要知道这个例子就可以了：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">const</span> getProp <span class="token operator">=</span> <span class="token operator">&lt;</span>T<span class="token punctuation">,</span> K <span class="token keyword">extends</span> <span class="token class-name">keyof</span> T<span class="token operator">&gt;</span><span class="token punctuation">(</span>object<span class="token punctuation">:</span> T<span class="token punctuation">,</span> propName<span class="token punctuation">:</span> K<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> object<span class="token punctuation">[</span>propName<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> obj <span class="token operator">=</span> <span class="token punctuation">{</span> a<span class="token punctuation">:</span> <span class="token string">"aa"</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token string">"bb"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">getProp</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> <span class="token string">"c"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 类型“"c"”的参数不能赋给类型“"a" | "b"”的参数</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">这里我们使用让<code>K</code>来继承索引类型<code>keyof T</code>，你可以理解为<code>keyof T</code>相当于一个由泛型变量T的属性名构成的联合类型，在这里 K 就被约束为了只能是"a"或"b"，所以当我们传入字符串"c"想要获取对象<em>obj</em>的属性"c"时就会报错。</p>
</div><div class="cl-preview-section"><h2 id="小结" style="font-size: 30px;">小结</h2>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">本小节我们学习了泛型的相关知识；学习了使用泛型来弥补使用any造成的类型信息缺失；当我们的类型是灵活任意的，又要准确使用类型信息时，就需要使用泛型来关联类型信息，其中离不开的是泛型变量；泛型变量可以是多个，且命名随意；如果需要对泛型变量的类型做进一步的限制，则需要用到我们最后讲的泛型约束；使用泛型约束通过<code>extends</code>关键字指定要符合的类型，从而满足更多场景的需求。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">下个小节我们将学习<strong>类</strong>的知识，学习TypeScript中的类的知识之前，你需要先详细学习ES6标准中新增的类的知识，建议你先学习下阮一峰的<a href="http://es6.ruanyifeng.com/">《ECMAScript 6 入门》</a>中类的部分。之所以要学习ES6中的类，是因为TypeScript中类的语法基本上是遵循ES6标准的，但是有一些区别，我们会在下个小节学习。<br>
<img src="http://img.mukewang.com/5cf4c0120001489616000663.jpg" alt="图片描述" data-original="http://img.mukewang.com/5cf4c0120001489616000663.jpg" class="" style="cursor: pointer;"></p>
</div></div>
            </div>
                            <!-- 买过的阅读 -->
                <div class="art-next-prev clearfix">
                                                                        <!-- 已买且开放 或者可以试读 -->
                            <a href="/read/35/article/348">
                                                    <div class="prev l clearfix">
                                <div class="icon l">
                                    <i class="imv2-arrow3_l"></i>
                                </div>
                                <p>
                                    11 为函数和函数参数定义类型
                                </p>
                            </div>
                        </a>
                                                                                            <!-- 已买且开放 或者可以试读 -->
                            <a href="/read/35/article/350">
                                                    <div class="next r clearfix">
                                <p>
                                    13 TS中的类，小心它与ES标准的差异
                                </p>
                                <div class="icon r">
                                    <i class="imv2-arrow3_r"></i>
                                </div>

                            </div>
                        </a>
                                    </div>
                    </div>
        <div class="comments-con js-comments-con" id="coments_con">
        </div>



    </div>
    
    
    

</div>
 
<!-- 专栏介绍页专栏评价 -->

<!-- 专栏介绍页底部三条评价 -->

<!-- 专栏阅读页弹层目录和介绍页页面目录 -->

<!-- 专栏阅读页发布回复 -->

<!-- 专栏阅读页发布评论 -->

<!-- 专栏阅读页底部评论 -->

<!-- 专栏阅读 单个 评论 -->

<!-- 新增回复和展开三条以外回复 -->

<!-- 立即订阅的弹窗 -->












</div></body></html>